Skip to content

feat(expression): cast numeric literals to decimal type#805

Open
huan233usc wants to merge 7 commits into
apache:mainfrom
huan233usc:feat/default-values-numeric-decimal-cast
Open

feat(expression): cast numeric literals to decimal type#805
huan233usc wants to merge 7 commits into
apache:mainfrom
huan233usc:feat/default-values-numeric-decimal-cast

Conversation

@huan233usc

@huan233usc huan233usc commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

What

Add casting of numeric literals (int, long, float, double) to a decimal target type in Literal::CastTo, so a numeric value can be used as a default for a decimal column.

Previously CastFromInt / CastFromLong / CastFromFloat / CastFromDouble had no kDecimal case and fell through to NotSupported, so a default like Literal::Int(12) or Literal::Double(9.99) for a decimal(9, 2) column was rejected. Java allows these (IntegerLiteral.to, DoubleLiteral.to, etc. scale the value to the target scale), so this brings the C++ literal cast layer to parity for numeric sources.

How

  • Integer → decimal: CastIntegerToDecimal scales the integer (scale 0) up to the target scale via Decimal::Rescale(0, scale), then verifies the result fits the target precision (FitsInPrecision). Example: 12decimal(9,2) yields unscaled 1200 (12.00).
  • Float/double → decimal: CastRealToDecimal parses the value's shortest round-tripping decimal representation (matching Java's BigDecimal.valueOf(double) via Double.toString), then rounds to the target scale with HALF_UP rounding (round half away from zero, as Java does — 2.53, -2.5-3), and checks precision. Non-finite values are rejected.
  • Both paths reject an out-of-range decimal scale before indexing the powers-of-ten table (DecimalType does not bound its scale on construction, so decimal(9, 40) would otherwise read past the table).

Scope

Follow-up split out from the v3 default-value work (see the CastDefaultToType discussion on #793). It only extends the shared Literal::CastTo layer for numeric sources.

Testing

LiteralTest.IntegerCastToDecimal (int/long scaling, out-of-precision rejection, out-of-range scale rejection) and LiteralTest.RealCastToDecimal (float/double scaling, HALF_UP rounding incl. negative, round-down, out-of-precision and non-finite rejection), all verified fail-without / pass-with. Full expression_test passes (495 tests).

@huan233usc huan233usc changed the title feat(expression): cast integer literals to decimal type feat(expression): cast numeric literals to decimal type Jul 3, 2026
@huan233usc
huan233usc marked this pull request as ready for review July 3, 2026 21:18
Comment thread src/iceberg/expression/literal.cc Outdated
Comment thread src/iceberg/expression/literal.cc Outdated
@huan233usc
huan233usc force-pushed the feat/default-values-numeric-decimal-cast branch from e5e3610 to 09a45b6 Compare July 12, 2026 21:20
@manuzhang manuzhang added this to the 0.4.0 milestone Jul 21, 2026
@manuzhang
manuzhang requested a review from Copilot July 21, 2026 04:09

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR extends Literal::CastTo to support casting numeric literals (int, long, float, double) into a decimal target type, aligning C++ literal-cast behavior with Java’s numeric-to-decimal default handling. It adds new decimal-cast logic for integer and real sources and introduces targeted unit tests to validate scaling, rounding, and rejection behavior.

Changes:

  • Add integer→decimal and real→decimal cast paths in LiteralCaster, including HALF_UP rounding behavior.
  • Add RescaleHalfUp helper to support HALF_UP rounding (including negative target scales) while avoiding unsafe power-of-ten indexing in some cases.
  • Add new tests covering integer/real decimal casts, scale handling, rounding behavior, and error cases.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

File Description
src/iceberg/expression/literal.cc Adds numeric→decimal casting logic and a HALF_UP rescaling helper used by Literal::CastTo.
src/iceberg/test/literal_test.cc Adds unit tests validating integer/real casts to decimal, rounding rules, and error handling.

Comment thread src/iceberg/expression/literal.cc Outdated
Comment thread src/iceberg/expression/literal.cc
Comment thread src/iceberg/expression/literal.cc Outdated
Comment thread src/iceberg/expression/literal.cc
Validate target scale bounds, avoid int128 overflow in HALF_UP by
comparing against divisor/2, and use std::to_chars for shortest
round-trip conversion.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants